// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Author: Markus Gutschke

#include <string.h>

#include "check.h"
#include "base64.h"

size_t b64encode(char *dst, const char *src, size_t len) {
  static const char alphabet[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  const char *d = dst;
  int bits = 0;
  unsigned c = 0;
  int pad = 0;
  while ((ssize_t)len-- > 0) {
    c = (c << 8) | *(unsigned char *)src++;
    bits += 8;
  drain:
    while (bits >= 6) {
      *dst++ = alphabet[(c >> (bits -= 6)) & 0x3F];
    }
  }
  if (bits) {
    pad = (6-bits)/2;
    c <<= 6-bits;
    bits = 6;
    goto drain;
  }
  strcpy(dst, "==" + (2-pad));
  return dst - d + strlen(dst);
}

size_t b64decode(char *dst, const char *src, size_t len) {
  char *d = dst;
  int bits = 0;
  unsigned c = 0;
  while ((ssize_t)len-- > 0) {
    unsigned char ch = (unsigned char)*src++;
    if (ch >= 'A' && ch <= 'Z') {
      ch -= 'A';
    } else if (ch >= 'a' && ch <= 'z') {
      ch -= 'a' - 26;
    } else if (ch >= '0' && ch <= '9') {
      ch -= '0' - 52;
    } else if (ch == '+' || ch == '-') {
      ch = 62;
    } else if (ch == '/') {
      ch = 63;
    } else {
      check(ch == '=' && len < 2);
      break;
    }
    c = (c << 6) | ch;
    if ((bits += 6) >= 8) {
      *dst++ = c >> (bits -= 8);
    }
  }
  return dst - d;
}
